package com.ybchen.core;

import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: 陈彦斌
 * @create: 2025-10-14 17:12
 */
public class MyFeignProxyFactory implements InvocationHandler {

    private final Class<?> targetType;
    private final String baseUrl;
    private final RestTemplate restTemplate = new RestTemplate();

    public MyFeignProxyFactory(Class<?> targetType, String baseUrl) {
        this.targetType = targetType;
        this.baseUrl = baseUrl;
    }

    @SuppressWarnings("unchecked")
    public <T> T createProxy() {
        return (T) Proxy.newProxyInstance(
                targetType.getClassLoader(),
                new Class[]{targetType},
                this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        }
        RequestMeta meta = resolveRequestMeta(method);
        Map<String, Object> queryParams = new LinkedHashMap<>();
        Object body = null;
        Parameter[] parameters = method.getParameters();
        if (args != null) {
            for (int i = 0; i < parameters.length; i++) {
                Parameter p = parameters[i];
                Object value = args[i];

                if (p.isAnnotationPresent(RequestBody.class)) {
                    body = value;
                } else {
                    String name = p.getName();
                    RequestParam reqParam = p.getAnnotation(RequestParam.class);
                    if (reqParam != null && !reqParam.value().isEmpty()) {
                        name = reqParam.value();
                    }
                    queryParams.put(name, value);
                }
            }
        }
        String fullUrl = buildUrl(meta.url, queryParams);

        System.out.println("【MyFeign】调用远程接口:");
        System.out.println("  方法: " + meta.method);
        System.out.println("  URL: " + fullUrl);
        System.out.println("  Body: " + body);

        // 发起HTTP请求
        if ("GET".equalsIgnoreCase(meta.method)) {
            return restTemplate.getForObject(fullUrl, String.class);
        } else if ("POST".equalsIgnoreCase(meta.method)) {
            return restTemplate.postForObject(fullUrl, body, String.class);
        } else if ("PUT".equalsIgnoreCase(meta.method)) {
            restTemplate.put(fullUrl, body);
            return null;
        } else if ("DELETE".equalsIgnoreCase(meta.method)) {
            restTemplate.delete(fullUrl);
            return null;
        } else {
            throw new UnsupportedOperationException("Unsupported HTTP method: " + meta.method);
        }
    }

    private RequestMeta resolveRequestMeta(Method method) {
        String path = "";
        String httpMethod = "GET"; // 默认 GET

        if (method.isAnnotationPresent(GetMapping.class)) {
            GetMapping ann = method.getAnnotation(GetMapping.class);
            path = firstOrEmpty(ann.value(), ann.path());
            httpMethod = "GET";
        } else if (method.isAnnotationPresent(PostMapping.class)) {
            PostMapping ann = method.getAnnotation(PostMapping.class);
            path = firstOrEmpty(ann.value(), ann.path());
            httpMethod = "POST";
        } else if (method.isAnnotationPresent(PutMapping.class)) {
            PutMapping ann = method.getAnnotation(PutMapping.class);
            path = firstOrEmpty(ann.value(), ann.path());
            httpMethod = "PUT";
        } else if (method.isAnnotationPresent(DeleteMapping.class)) {
            DeleteMapping ann = method.getAnnotation(DeleteMapping.class);
            path = firstOrEmpty(ann.value(), ann.path());
            httpMethod = "DELETE";
        } else if (method.isAnnotationPresent(RequestMapping.class)) {
            RequestMapping ann = method.getAnnotation(RequestMapping.class);
            path = firstOrEmpty(ann.value(), ann.path());
            if (ann.method().length > 0) {
                httpMethod = ann.method()[0].name();
            }
        } else {
            // 默认规则：方法名映射为路径
            path = "/" + method.getName();
        }

        // 组合完整路径
        String url = baseUrl + path;
        return new RequestMeta(httpMethod, url);
    }

    private String firstOrEmpty(String[]... arrays) {
        for (String[] arr : arrays) {
            if (arr != null && arr.length > 0 && !arr[0].isEmpty()) {
                return arr[0];
            }
        }
        return "";
    }

    private String buildUrl(String baseUrl, Map<String, Object> queryParams) {
        if (queryParams.isEmpty()) return baseUrl;
        String queryString = queryParams.entrySet().stream()
                .map(e -> {
                    try {
                        return e.getKey() + "=" + URLEncoder.encode(String.valueOf(e.getValue()), StandardCharsets.UTF_8.toString());
                    } catch (UnsupportedEncodingException ex) {
                        throw new RuntimeException(ex);
                    }
                })
                .collect(Collectors.joining("&"));
        return baseUrl + (baseUrl.contains("?") ? "&" : "?") + queryString;
    }

    private static class RequestMeta {
        final String method;
        final String url;

        RequestMeta(String method, String url) {
            this.method = method;
            this.url = url;
        }
    }
}
